﻿using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.Mvc;

using Library.API.C4.Models;
using Library.API.C4.Services;

using System;
using System.Collections.Generic;
using System.Linq;

namespace Library.API.C4.Controllers
{
    /// <summary>
    /// 作者/某xx/书籍
    /// //RESTful api设计风格,它指定到某个作者authorId的资源，请求该控制器时，必须带api/authors/{authorId}/books，完整示例：
    /// http://localhost:44349/api/authors/200/books http会自动转发到https请求，因为请求通道中配置了UseHttpsRedirection,200代表{authorId}
    /// </summary>
    [Route("api/authors/{authorId}/books")]
    [ApiController]
    public class BookController : ControllerBase
    {
        //  自动注入实例，因为添加了AddScoped依赖注入服务
        public BookController(IBookRepository bookRepository, IAuthorRepository authorRepository)
        {
            AuthorRepository = authorRepository;
            BookRepository = bookRepository;
        }

        public IAuthorRepository AuthorRepository { get; }
        public IBookRepository BookRepository { get; }

        /// <summary>
        /// 删除书籍
        /// httpDelete操作
        /// http://localhost:44349/api/authors/200/books/3
        /// </summary>
        /// <returns></returns>
        [HttpDelete("{bookID}")]
        public IActionResult DeleteBook(Guid authorId, Guid bookId)
        {
            if (!AuthorRepository.IsAuthorExists(authorId))
            {
                return NotFound();  //  这是MVC默认返回的结果，它将返回404
            }

            var book = BookRepository.GetBookForAuthor(authorId, bookId);
            if (book == null)
            {
                return NotFound();
            }

            BookRepository.DeleteBook(book);
            return NoContent(); //  这是MVC默认返回的结果，它将返回空内容
        }

        /// <summary>
        /// 更新书籍
        /// http://localhost:44349/api/authors/200/books/3
        /// </summary>
        /// <param name="authorId"></param>
        /// <param name="bookId"></param>
        /// <param name="updatedBook">json对象</param>
        /// <returns></returns>
        [HttpPut("{bookId}")]
        public IActionResult UpdateBook(Guid authorId, Guid bookId, BookForUpdateDto updatedBook)
        {
            if (!AuthorRepository.IsAuthorExists(authorId))
            {
                return NotFound();
            }

            var book = BookRepository.GetBookForAuthor(authorId, bookId);
            if (book == null)
            {
                return NotFound();
            }

            BookRepository.UpdateBook(authorId, bookId, updatedBook);
            return NoContent();
        }

        /// <summary>
        /// 批量更新书籍
        /// http://localhost:44349/api/authors/200/books/3
        /// </summary>
        /// <param name="authorId"></param>
        /// <param name="bookId"></param>
        /// <param name="patchDocument">
        /// JSON Patch是一种描述JSON文档更改的格式
        /// 常见操作：Add、Move、Replace、Remove、copy
        /// </param>
        /// <returns></returns>
        [HttpPatch("{bookId}")]
        public IActionResult ParticallyUpdateBook(Guid authorId, Guid bookId, JsonPatchDocument<BookForUpdateDto> patchDocument)
        {
            if (!AuthorRepository.IsAuthorExists(authorId))
            {
                return NotFound();
            }

            var book = BookRepository.GetBookForAuthor(authorId, bookId);
            if (book == null)
            {
                return NotFound();
            }

            var bookToPatch = new BookForUpdateDto
            {
                Title = book.Title,
                Description = book.Description,
                Pages = book.Pages
            };

            patchDocument.ApplyTo(bookToPatch);//   将http请求的json更改格式应用到对象中
            if (!ModelState.IsValid)    //  ModelState验证模型是否正确，一般在模型中会增加约束特性
            {
                return BadRequest(ModelState);  //  BadRequest执行时将生成错误请求 (400) 响应
            }

            BookRepository.UpdateBook(authorId, bookId, bookToPatch);
            return NoContent();
        }

        /// <summary>
        /// 添加书籍
        /// http://localhost:44349/api/authors/200/books
        /// </summary>
        /// <param name="authorId"></param>
        /// <param name="bookForCreationDto">json对象</param>
        /// <returns></returns>
        [HttpPost()]
        public IActionResult AddBook(Guid authorId, BookForCreationDto bookForCreationDto)
        {
            if (!AuthorRepository.IsAuthorExists(authorId))
            {
                return NotFound();
            }

            var newBook = new BookDto
            {
                Id = Guid.NewGuid(),
                Title = bookForCreationDto.Title,
                Description = bookForCreationDto.Description,
                Pages = bookForCreationDto.Pages,
                AuthorId = authorId,
            };

            BookRepository.AddBook(newBook);
            return CreatedAtRoute(nameof(GetBook), new { bookId = newBook.Id }, newBook);   //  CreatedAtRoute创建一个重定向路由结果，它将跳转到GetBook方法，并传递参数
        }
        /// <summary>
        /// 获取书籍
        /// http://localhost:44349/api/authors/200/books/3
        /// </summary>
        /// <param name="authorId"></param>
        /// <param name="bookId"></param>
        /// <returns></returns>
        [HttpGet("{bookId}", Name = nameof(GetBook))]
        public ActionResult<BookDto> GetBook(Guid authorId, Guid bookId)
        {
            if (!AuthorRepository.IsAuthorExists(authorId))
            {
                return NotFound();
            }

            var targetBook = BookRepository.GetBookForAuthor(authorId, bookId);
            if (targetBook == null)
            {
                return NotFound();
            }

            return targetBook;
        }
        /// <summary>
        /// 获取该作者下所有书籍
        /// http://localhost:44349/api/authors/200/books
        /// </summary>
        /// <param name="authorId"></param>
        /// <returns></returns>
        [HttpGet()]
        public ActionResult<List<BookDto>> GetBooks(Guid authorId)
        {
            if (!AuthorRepository.IsAuthorExists(authorId))
            {
                return NotFound();
            }

            return BookRepository.GetBooksForAuthor(authorId).ToList();
        }
    }
}
/** JsonPatchDocument详细文档：
NuGet =   Microsoft.AspNetCore.JsonPatch
 
简单例子：
假设数据库中对象的内容是这个：
{
  "baz": "qux",
  "foo": "bar"
}
http请求内容中需要变更的内容是这个，那么使用 JsonPatchDocument将会对baz进行更新,hello进行添加，foo进行删除
[
  { "op": "replace", "path": "/baz", "value": "boo" },
  { "op": "add", "path": "/hello", "value": ["world"] },
  { "op": "remove", "path": "/foo" }
]
通过调用ApplyTo方法，获得最终更新结果
{
  "baz": "boo",
  "hello": ["world"]
}

例子2：
【服务端】
[HttpPost("/Orders/PostTest")]
public Dictionary<string, string> PostTest([FromBody]JsonPatchDocument<IDictionary<string, string>> body)
{
    Dictionary<string, string> dict = new Dictionary<string, string> { { "name", "fan" }, { "age", "18" } };
    body.ApplyTo(dict);
    return dict;
}

public string GetTest([FromBody]JsonPatchDocument<User> body)
{
    User u = new User();
    body.ApplyTo(u);
    return "true";
}
【客户端】
HttpClient client = new HttpClient();
string responseText = client.PostAsync("http://localhost:7777/webapi/a1/orders/posttest", "[{\"op\" : \"replace\",\"path\" : \"/name\",\"value\" : \"fanfan\"},{\"op\" : \"add\",\"path\" : \"/class\",\"value\" : \"333\"}]", null,Encoding.UTF8).Result;

【返回结果】
{
  "name": "fanfan",
  "age": "18",
  "class": "333"
}
//
 */